package com.lovezy.platform.notice.service.impl;

import com.github.pagehelper.PageInfo;
import com.lovezy.platform.core.base.enums.StatusEnum;
import com.lovezy.platform.core.base.enums.TrueOrFalseEnum;
import com.lovezy.platform.core.base.query.Pager;
import com.lovezy.platform.core.base.service.MapperService;
import com.lovezy.platform.core.exception.DefaultErrorCode;
import com.lovezy.platform.core.exception.ServiceException;
import com.lovezy.platform.core.mq.MessageProducer;
import com.lovezy.platform.core.utils.ObjectUtil;
import com.lovezy.platform.core.valid.ValidatorUtil;
import com.lovezy.platform.message.push.PushEntity;
import com.lovezy.platform.message.push.PushIType;
import com.lovezy.platform.message.push.PushMessage;
import com.lovezy.platform.message.push.SinglePushMessage;
import com.lovezy.platform.notice.enums.NoticeSourceTypeEnum;
import com.lovezy.platform.notice.form.NoticeForm;
import com.lovezy.platform.notice.mapper.NoticeMapper;
import com.lovezy.platform.notice.model.Notice;
import com.lovezy.platform.notice.model.NoticeExample;
import com.lovezy.platform.notice.query.NoticeQuery;
import com.lovezy.platform.notice.service.NoticeMemberService;
import com.lovezy.platform.notice.service.NoticeService;
import com.lovezy.platform.notice.vo.NoticeMemberVo;
import com.lovezy.platform.notice.vo.NoticeVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Optional;

import static com.lovezy.platform.core.utils.ObjectUtil.nonNull;

/**
 * Created by jin on 2017/12/9.
 */
@Service
public class NoticeServiceImpl extends MapperService<Notice,Integer,NoticeMapper> implements NoticeService{

    @Autowired
    private NoticeMemberService noticeMemberService;

    @Autowired
    @Qualifier("pushMessageProducer")
    private MessageProducer pushMessageProducer;

    @Override
    @Async
    public Notice newNotice(NoticeForm form) {
        ValidatorUtil.validate(form);
        Integer sourceId = form.getSourceId();
        NoticeSourceTypeEnum sourceType = form.getSourceType();
        String mid = form.getMid();
        String operator = form.getOperator();
        Notice thisNotice;

        if (sourceType.needAddMember()) {
            Optional<Notice> notice = findNotice(sourceId, sourceType, mid);
            thisNotice = notice.orElseGet(() -> addNotice(sourceId, sourceType, mid, operator));
            noticeMemberService.newNoticeMember(thisNotice, operator);
        } else {
            thisNotice = addNotice(sourceId, sourceType, mid, operator);
        }

        pushMessage(thisNotice);
        return thisNotice;
    }


    private void pushMessage(Notice notice) {
        Optional<NoticeVo> noticeVo = findNoticeVoById(notice.getNoticeId());
        noticeVo.ifPresent(n -> {
            PushMessage<NoticeVo> message = new SinglePushMessage<>();
            NoticeSourceTypeEnum noticeType = NoticeSourceTypeEnum.valueOf(n.getType());
            String prefixName = n.getOperatorName();
            String content = prefixName + noticeType.prefix() + n.getData();
            message.setContent(content);
            message.setEntity(new PushEntity<>(PushIType.NOTICE, n));
            message.setReceiverMemberId(notice.getMemberId());
//            pushService.pushMessage(message);
            pushMessageProducer.send(message);
        });


    }

    private Optional<NoticeVo> findNoticeVoById(Integer noticeId) {
        return Optional.ofNullable(mapper.findNoticeVo(noticeId));
    }

    @Override
    public void deleteNotice(Notice notice) {
        String memberId = notice.getMemberId();
        Integer noticeId = notice.getNoticeId();
        boolean hasNullValue = ObjectUtil.ifNull(memberId, notice);
        if (hasNullValue) {
            throw new ServiceException(DefaultErrorCode.VALID_ERROR, "通知ID不能为空");
        }

        Notice dbNotice = mapper.selectByPrimaryKey(noticeId);
        if (dbNotice == null || !dbNotice.getMemberId().equals(memberId)) {
            throw new ServiceException("无权限删除此通知");
        }
        Notice update = new Notice();
        update.setNoticeId(noticeId);
        update.setStatus(StatusEnum.DELETED.value());
        update.setGmtModify(new Date());
        mapper.updateByPrimaryKeySelective(update);
    }

    @Override
    public PageInfo<NoticeVo> findNoticeList(NoticeQuery query) {
        String mid = query.getMid();
        nonNull(mid);
        PageInfo<NoticeVo> notices = Pager.doPageInfo(query, () -> mapper.findNoticeList(query));
        readAllNotice(query);
        notices.getList().forEach(this::noticeTypeHandle);
        return notices;
    }

    @Override
    public Integer notReadNotice(NoticeQuery query) {
        String mid = query.getMid();
        nonNull(mid);
        NoticeExample example = new NoticeExample();
        example.createCriteria()
                .andMemberIdEqualTo(mid)
                .andReadEqualTo(TrueOrFalseEnum.FALSE.value())
                .andStatusEqualTo(StatusEnum.NORMAL.value());
        return mapper.countByExample(example);
    }

    @Override
    public void readAllNotice(NoticeQuery query) {
        String mid = query.getMid();
        nonNull(mid);
        mapper.readAllNotice(mid);
    }



    private void noticeTypeHandle(NoticeVo noticeVo) {
        NoticeSourceTypeEnum noticeType = NoticeSourceTypeEnum.valueOf(noticeVo.getType());

        String prefixName = noticeVo.getOperatorName();
        if (noticeType.needAddMember()) {
            NoticeMemberVo noticeMembers = noticeMemberService.findNoticeMembers(noticeVo.getNoticeId());
            Integer num = noticeMembers.getNum();
            prefixName = noticeMembers.getNames()
                    + (num >= 2 ? "等" + num + "人" : "")
                    + noticeType.prefix();
        }

        String content = noticeVo.getData();
        String fullContent = prefixName + content;
        noticeVo.setData(fullContent);
    }

    private Notice addNotice(Integer sourceId,NoticeSourceTypeEnum sourceType,String mid,String operator) {
        Notice notice = new Notice();
        Date now = new Date();
        notice.setSourceId(sourceId);
        notice.setSourceType(sourceType.value());
        notice.setMemberId(mid);
        notice.setOperator(operator);
        notice.setGmtCreate(now);
        notice.setGmtModify(now);
        notice.setStatus(StatusEnum.NORMAL.value());
        notice.setRead(TrueOrFalseEnum.FALSE.value());
        mapper.insert(notice);
        return notice;
    }



    private Optional<Notice> findNotice(Integer sourceId, NoticeSourceTypeEnum sourceType, String mid) {
        NoticeExample example = new NoticeExample();
        example.createCriteria()
                .andSourceIdEqualTo(sourceId)
                .andSourceTypeEqualTo(sourceType.value())
                .andMemberIdEqualTo(mid);
        return Pager.doSingleton(() -> mapper.selectByExample(example));
    }

}
